<html>
  <head>
	  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>i5ting_ztree_toc:</title>
		<link href="toc/style/github-bf51422f4bb36427d391e4b75a1daa083c2d840e.css" media="all" rel="stylesheet" type="text/css"/>
		<link href="toc/style/github2-d731afd4f624c99a4b19ad69f3083cd6d02b81d5.css" media="all" rel="stylesheet" type="text/css"/>
		<link href="toc/css/zTreeStyle/zTreeStyle.css" media="all" rel="stylesheet" type="text/css"/>
	  <style>
		pre {
		    counter-reset: line-numbering;
		    border: solid 1px #d9d9d9;
		    border-radius: 0;
		    background: #fff;
		    padding: 0;
		    line-height: 23px;
		    margin-bottom: 30px;
		    white-space: pre;
		    overflow-x: auto;
		    word-break: inherit;
		    word-wrap: inherit;
		}

		pre a::before {
		  content: counter(line-numbering);
		  counter-increment: line-numbering;
		  padding-right: 1em; /* space after numbers */
		  width: 25px;
		  text-align: right;
		  opacity: 0.7;
		  display: inline-block;
		  color: #aaa;
		  background: #eee;
		  margin-right: 16px;
		  padding: 2px 10px;
		  font-size: 13px;
		  -webkit-touch-callout: none;
		  -webkit-user-select: none;
		  -khtml-user-select: none;
		  -moz-user-select: none;
		  -ms-user-select: none;
		  user-select: none;
		}

		pre a:first-of-type::before {
		  padding-top: 10px;
		}

		pre a:last-of-type::before {
		  padding-bottom: 10px;
		}

		pre a:only-of-type::before {
		  padding: 10px;
		}

		.highlight { background-color: #ffffcc } /* RIGHT */
		</style>
  </head>
  <body>
	  <div>
				<div style='width:25%;'>
						<ul id="tree" class="ztree" style='width:100%'>

						</ul>
				</div>
        <div id='readme' style='width:70%;margin-left:20%;'>
          	<article class='markdown-body'>
            	<h1 id="-node-js-">一、初识Node.js与内置模块</h1>
<h2 id="1-1-javascript-">1.1 浏览器中的JavaScript的运行环境</h2>
<ul>
<li>运行环境是指代码正常运行所需的必要环境。</li>
</ul>
<p>① V8 引擎负责解析和执行 JavaScript 代码。</p>
<p>② 内置 API 是由运行环境提供的特殊接口，只能在所属的运行环境中被调用。</p>
<p><img src=".\assets\浏览器中的js运行环境.png" alt=""></p>
<h2 id="1-2-node-js-">1.2 Node.js简介</h2>
<h3 id="-">概念</h3>
<ul>
<li>Node.js® is a JavaScript runtime built on Chrome&#39;s V8 JavaScript engine.</li>
<li>Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。</li>
<li>Node.js 的官网地址： <a href="https://nodejs.org/zh-cn/">https://nodejs.org/zh-cn/</a></li>
</ul>
<h3 id="-">运行环境</h3>
<p>思考Node.js 中的 JavaScript 运行环境</p>
<ul>
<li><p>注意：</p>
<p>① 浏览器是 JavaScript 的前端运行环境。</p>
<p>② Node.js 是 JavaScript 的后端运行环境。</p>
<p>③ Node.js 中无法调用 DOM 和 BOM 等</p>
<p>浏览器内置 API。</p>
</li>
</ul>
<p><img src=".\assets\nodejs运行环境.png" alt=""></p>
<h3 id="-">应用</h3>
<p>​    Node.js 作为一个 JavaScript 的运行环境，仅仅提供了基础的功能和 API。然而，基于 Node.js 提供的这些基础能，很多强大的工具和框架如雨后春笋，层出不穷，所以学会了 Node.js ，可以让前端程序员胜任更多的工作和岗位：</p>
<p>① 基于 Express 框架（<a href="http://www.expressjs.com.cn/），可以快速构建">http://www.expressjs.com.cn/），可以快速构建</a> Web 应用</p>
<p>② 基于 Electron 框架（<a href="https://electronjs.org/），可以构建跨平台的桌面应用">https://electronjs.org/），可以构建跨平台的桌面应用</a></p>
<p>③ 基于 restify 框架（<a href="http://restify.com/），可以快速构建">http://restify.com/），可以快速构建</a> API 接口项目</p>
<p>④ 读写和操作数据库、创建实用的命令行工具辅助前端开发、etc…</p>
<p>总之：Node.js 是大前端时代的“大宝剑”，有了 Node.js 这个超级 buff 的加持，前端程序员的行业竞争力会越来越强！</p>
<hr>
<h2 id="1-3-node-js-">1.3 Node.js环境安装</h2>
<p>​        如果希望通过 Node.js 来运行 Javascript 代码，则必须在计算机上安装 Node.js 环境才行。</p>
<p>​        安装包可以从 Node.js 的官网首页直接下载，进入到 Node.js 的官网首页（<strong><a href="https://nodejs.org/en/">https://nodejs.org/en/</a></strong>），点击绿色的按钮，下载所需的版本后，双击直接安装即可。</p>
<p><strong>区分 LTS 版本和 Current 版本的不同</strong></p>
<p>① LTS 为长期稳定版，对于追求稳定性的企业级项目来说，推荐安装 LTS 版本的 Node.js。</p>
<p>② Current 为新特性尝鲜版，对热衷于尝试新特性的用户来说，推荐安装 Current 版本的 Node.js。但是，Current 版本中可能存在隐藏的 Bug 或安全性漏洞，因此不推荐在企业级项目中使用 Current 版本的 Node.js。</p>
<p><strong>查看已安装的 Node.js 的版本号</strong></p>
<p>​    打开终端，在终端输入命令 node –v 后，按下回车键，即可查看已安装的 Node.js 的版本号。</p>
<p>​    Windows 系统快速打开终端的方式：使用快捷键（Windows徽标键 + R）打开运行面板，输入 cmd 后直接回车，即可打开终端。</p>
<h1 id="-">二、内置模块</h1>
<h2 id="2-1-fs-">2.1 fs文件系统模块</h2>
<h3 id="-readfile-">使用readFile方法读取文件的内容</h3>
<pre><code class="lang-javascript">// 1. 导入 fs 模块，来操作文件
const fs = require(&#39;fs&#39;)

// 2. 调用 fs.readFile() 方法读取文件
//    参数1：读取文件的存放路径
//    参数2：读取文件时候采用的编码格式，一般默认指定 utf8
//    参数3：回调函数，拿到读取失败和成功的结果  err  dataStr
fs.readFile(&#39;./files/1.txt&#39;, &#39;utf8&#39;, function (err, dataStr) {
  // 2.1 打印失败的结果
  // 如果读取成功，则 err 的值为 null
  // 如果读取失败，则 err 的值为 错误对象，dataStr 的值为 undefined
  console.log(err)
  console.log(&#39;-------&#39;)
  // 2.2 打印成功的结果
  console.log(dataStr)
})

</code></pre>
<h3 id="-">判断文件是否成功</h3>
<pre><code class="lang-javascript">const fs = require(&#39;fs&#39;)

fs.readFile(&#39;./files/1.txt&#39;, &#39;utf8&#39;, function (err, dataStr) {
  if (err) {
    return console.log(&#39;读取文件失败！&#39; + err.message)
  }
  console.log(&#39;读取文件成功！&#39; + dataStr)
})

</code></pre>
<h3 id="-">写入文件内容</h3>
<pre><code class="lang-javascript">// 1. 导入 fs 文件系统模块
const fs = require(&#39;fs&#39;)

// 2. 调用 fs.writeFile() 方法，写入文件的内容
//    参数1：表示文件的存放路径
//    参数2：表示要写入的内容
//    参数3：回调函数
fs.writeFile(&#39;./files/3.txt&#39;, &#39;ok123&#39;, function(err) {
  // 2.1 如果文件写入成功，则 err 的值等于 null
  // 2.2 如果文件写入失败，则 err 的值等于一个 错误对象
  // console.log(err)

  if (err) {
    return console.log(&#39;文件写入失败！&#39; + err.message)
  }
  console.log(&#39;文件写入成功！&#39;)
})

</code></pre>
<h3 id="-">整理成绩</h3>
<pre><code class="lang-javascript">// 1. 导入 fs 模块
const fs = require(&#39;fs&#39;)

// 2. 调用 fs.readFile() 读取文件的内容
// 成绩.txt 内容为：  小红=99 小白=100 小黄=70 小黑=66 小绿=88
fs.readFile(&#39;./files/成绩.txt&#39;, &#39;utf8&#39;, function (err, dataStr) {
  // 3. 判断是否读取成功
  if (err) {
    return console.log(&#39;读取文件失败！&#39; + err.message)
  }
  // console.log(&#39;读取文件成功！&#39; + dataStr)

  // 4.1 先把成绩的数据，按照空格进行分割
  const arrOld = dataStr.split(&#39; &#39;)
  // 4.2 循环分割后的数组，对每一项数据，进行字符串的替换操作
  const arrNew = []
  arrOld.forEach(item =&gt; {
    arrNew.push(item.replace(&#39;=&#39;, &#39;：&#39;))
  })
  // console.log(arrNew)
  // 4.3 把新数组中的每一项，进行合并，得到一个新的字符串
  const newStr = arrNew.join(&#39;\r\n&#39;)
  // console.log(newStr)

  // 5. 调用 fs.writeFile() 方法，把处理完毕的成绩，写入到新文件中
  fs.writeFile(&#39;./files/成绩-ok.txt&#39;, newStr, function (err) {
    if (err) {
      return console.log(&#39;写入文件失败！&#39; + err.message)
    }
    console.log(&#39;成绩写入成功！&#39;)
  })
})

</code></pre>
<h3 id="-">演示路径中的问题</h3>
<pre><code class="lang-javascript">const fs = require(&#39;fs&#39;)

// 出现路径拼接错误的问题，是因为提供了 ./ 或 ../ 开头的相对路径
// 如果要解决这个问题，可以直接提供一个完整的文件存放路径就行
/* fs.readFile(&#39;./files/1.txt&#39;, &#39;utf8&#39;, function(err, dataStr) {
  if (err) {
    return console.log(&#39;读取文件失败！&#39; + err.message)
  }
  console.log(&#39;读取文件成功！&#39; + dataStr)
}) */

// 移植性非常差、不利于维护
/* fs.readFile(&#39;C:\\Users\\escook\\Desktop\\Node.js基础\\day1\\code\\files\\1.txt&#39;, &#39;utf8&#39;, function(err, dataStr) {
  if (err) {
    return console.log(&#39;读取文件失败！&#39; + err.message)
  }
  console.log(&#39;读取文件成功！&#39; + dataStr)
}) */

// __dirname 表示当前文件所处的目录
console.log(__dirname)

fs.readFile(__dirname + &#39;/files/1.txt&#39;, &#39;utf8&#39;, function(err, dataStr) {
  if (err) {
    return console.log(&#39;读取文件失败！&#39; + err.message)
  }
  console.log(&#39;读取文件成功！&#39; + dataStr)
})

</code></pre>
<h2 id="2-2-path-">2.2 path路径</h2>
<h3 id="path-join-">path.join方法</h3>
<pre><code class="lang-javascript">const path = require(&#39;path&#39;)
const fs = require(&#39;fs&#39;)

// 注意：  ../ 会抵消前面的路径
// const pathStr = path.join(&#39;/a&#39;, &#39;/b/c&#39;, &#39;../../&#39;, &#39;./d&#39;, &#39;e&#39;)
// console.log(pathStr)  // \a\b\d\e

// fs.readFile(__dirname + &#39;/files/1.txt&#39;)

fs.readFile(path.join(__dirname, &#39;./files/1.txt&#39;), &#39;utf8&#39;, function(err, dataStr) {
  if (err) {
    return console.log(err.message)
  }
  console.log(dataStr)
})

</code></pre>
<h3 id="path-basename-">path.basename方法</h3>
<pre><code class="lang-javascript">const path = require(&#39;path&#39;)

// 定义文件的存放路径
const fpath = &#39;/a/b/c/index.html&#39;

// const fullName = path.basename(fpath)
// console.log(fullName)

const nameWithoutExt = path.basename(fpath, &#39;.html&#39;)
console.log(nameWithoutExt)

</code></pre>
<h3 id="path-extname-">path.extname方法</h3>
<pre><code class="lang-javascript">const path = require(&#39;path&#39;)

// 这是文件的存放路径
const fpath = &#39;/a/b/c/index.html&#39;

const fext = path.extname(fpath)
console.log(fext)

</code></pre>
<h3 id="-">时钟案例</h3>
<pre><code class="lang-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;

&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot;&gt;
  &lt;title&gt;index首页&lt;/title&gt;
  &lt;style&gt;
    html,
    body {
      margin: 0;
      padding: 0;
      height: 100%;
      background-image: linear-gradient(to bottom right, red, gold);
    }

    .box {
      width: 400px;
      height: 250px;
      background-color: rgba(255, 255, 255, 0.6);
      border-radius: 6px;
      position: absolute;
      left: 50%;
      top: 40%;
      transform: translate(-50%, -50%);
      box-shadow: 1px 1px 10px #fff;
      text-shadow: 0px 1px 30px white;

      display: flex;
      justify-content: space-around;
      align-items: center;
      font-size: 70px;
      user-select: none;
      padding: 0 20px;

      /* 盒子投影 */
      -webkit-box-reflect: below 0px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(0%, transparent), to(rgba(250, 250, 250, .2)));
    }
  &lt;/style&gt;
&lt;/head&gt;

&lt;body&gt;
  &lt;div class=&quot;box&quot;&gt;
    &lt;div id=&quot;HH&quot;&gt;00&lt;/div&gt;
    &lt;div&gt;:&lt;/div&gt;
    &lt;div id=&quot;mm&quot;&gt;00&lt;/div&gt;
    &lt;div&gt;:&lt;/div&gt;
    &lt;div id=&quot;ss&quot;&gt;00&lt;/div&gt;
  &lt;/div&gt;

  &lt;script&gt;
    window.onload = function () {
      // 定时器，每隔 1 秒执行 1 次
      setInterval(() =&gt; {
        var dt = new Date()
        var HH = dt.getHours()
        var mm = dt.getMinutes()
        var ss = dt.getSeconds()

        // 为页面上的元素赋值
        document.querySelector(&#39;#HH&#39;).innerHTML = padZero(HH)
        document.querySelector(&#39;#mm&#39;).innerHTML = padZero(mm)
        document.querySelector(&#39;#ss&#39;).innerHTML = padZero(ss)
      }, 1000)
    }

    // 补零函数
    function padZero(n) {
      return n &gt; 9 ? n : &#39;0&#39; + n
    }
  &lt;/script&gt;
&lt;/body&gt;

&lt;/html&gt;
</code></pre>
<h2 id="2-3-http-">2.3 http模块</h2>
<h3 id="-">服务器相关概念</h3>
<p>​        在网络节点中，负责消费资源的电脑，叫做客户端；负责对外提供网络资源的电脑，叫做服务器。</p>
<p>​        <strong>http 模块</strong>是 Node.js 官方提供的、用来创建 web 服务器的模块。通过 http 模块提供的 http.createServer() 方法，就能方便的把一台普通的电脑，变成一台 Web 服务器，从而对外提供 Web 资源服务。</p>
<pre><code class="lang-javascript">const http = require(&#39;http&#39;)
</code></pre>
<h4 id="ip-">IP地址</h4>
<p>​        <strong>IP 地址</strong>就是互联网上每台计算机的唯一地址，因此 IP 地址具有唯一性。如果把“个人电脑”比作“一台电话”，那么“IP地址”就相当于“电话号码”，只有在知道对方 IP 地址的前提下，才能与对应的电脑之间进行数据通信。</p>
<p>​        IP 地址的格式：通常用“点分十进制”表示成（a.b.c.d）的形式，其中，a,b,c,d 都是 0~255 之间的十进制整数。例如：用点分十进表示的 IP地址（192.168.1.1）</p>
<p>注意：</p>
<p><strong>① 互联网中每台 Web 服务器，都有自己的 IP 地址</strong>，例如：大家可以在 Windows 的终端中运行 ping <a href="http://www.baidu.com">www.baidu.com</a> 命令，即可查看到百度服务器的 IP 地址。</p>
<p>② 在开发期间，自己的电脑既是一台服务器，也是一个客户端，为了方便测试，可以在自己的浏览器中输入 127.0.0.1 这个IP 地址，就能把自己的电脑当做一台服务器进行访问了。</p>
<h4 id="-">域名和域名服务器</h4>
<p>​        尽管 IP 地址能够唯一地标记网络上的计算机，但IP地址是一长串数字，不直观，而且不便于记忆，于是人们又发明了另一套字符型的地址方案，即所谓的<strong>域名（Domain Name）地址</strong>。</p>
<p>​        IP地址和域名是一一对应的关系，这份对应关系存放在一种叫做<strong>域名服务器</strong>(DNS，Domain name server)的电脑中。使用者只需通过好记的域名访问对应的服务器即可，对应的转换工作由域名服务器实现。因此，<strong>域名服务器就是提供 IP 地址和域名之间的转换服务的服务器</strong>。</p>
<p>注意：</p>
<p>① 单纯使用 IP 地址，互联网中的电脑也能够正常工作。但是有了域名的加持，能让互联网的世界变得更加方便。</p>
<p>② 在开发测试期间， 127.0.0.1 对应的域名是 localhost，它们都代表我们自己的这台电脑，在使用效果上没有任何区别。</p>
<h4 id="-">端口号</h4>
<p>​    计算机中的端口号，就好像是现实生活中的门牌号一样。通过门牌号，外卖小哥可以在整栋大楼众多的房间中，准确把外卖送到你的手中。</p>
<p>​    同样的道理，在一台电脑中，可以运行成百上千个 web 服务。每个 web 服务都对应一个唯一的端口号。客户端发送过来的网络请求，通过端口号，可以被准确地交给对应的 web 服务进行处理。</p>
<p><img src=".\assets\端口号图片.png" alt=""></p>
<p>注意：</p>
<p>① 每个端口号不能同时被多个 web 服务占用。</p>
<p>② 在实际应用中，URL 中的 80 端口可以被省略。</p>
<h3 id="-web-">创建基本的web服务器</h3>
<pre><code class="lang-javascript">// 1. 导入 http 模块
const http = require(&#39;http&#39;)
// 2. 创建 web 服务器实例
const server = http.createServer()
// 3. 为服务器实例绑定 request 事件，监听客户端的请求
server.on(&#39;request&#39;, function (req, res) {
  console.log(&#39;Someone visit our web server.&#39;)
})
// 4. 启动服务器
server.listen(8080, function () {
  console.log(&#39;server running at http://127.0.0.1:8080&#39;)
})

</code></pre>
<h3 id="-req-">了解req请求对象</h3>
<pre><code class="lang-javascript">const http = require(&#39;http&#39;)
const server = http.createServer()
// req 是请求对象，包含了与客户端相关的数据和属性
server.on(&#39;request&#39;, (req, res) =&gt; {
  // req.url 是客户端请求的 URL 地址
  const url = req.url
  // req.method 是客户端请求的 method 类型
  const method = req.method
  const str = `Your request url is ${url}, and request method is ${method}`
  console.log(str)
  // 调用 res.end() 方法，向客户端响应一些内容
  res.end(str)
})
server.listen(80, () =&gt; {
  console.log(&#39;server running at http://127.0.0.1&#39;)
})

</code></pre>
<h3 id="-">解决中文乱码问题</h3>
<pre><code class="lang-javascript">const http = require(&#39;http&#39;)
const server = http.createServer()

server.on(&#39;request&#39;, (req, res) =&gt; {
  // 定义一个字符串，包含中文的内容
  const str = `您请求的 URL 地址是 ${req.url}，请求的 method 类型为 ${req.method}`
  // 调用 res.setHeader() 方法，设置 Content-Type 响应头，解决中文乱码的问题
  res.setHeader(&#39;Content-Type&#39;, &#39;text/html; charset=utf-8&#39;)
  // res.end() 将内容响应给客户端
  res.end(str)
})

server.listen(80, () =&gt; {
  console.log(&#39;server running at http://127.0.0.1&#39;)
})

</code></pre>
<h3 id="-url-html-">根据不同的url响应不同的html内容</h3>
<pre><code class="lang-javascript">const http = require(&#39;http&#39;)
const server = http.createServer()

server.on(&#39;request&#39;, (req, res) =&gt; {
  // 1. 获取请求的 url 地址
  const url = req.url
  // 2. 设置默认的响应内容为 404 Not found
  let content = &#39;&lt;h1&gt;404 Not found!&lt;/h1&gt;&#39;
  // 3. 判断用户请求的是否为 / 或 /index.html 首页
  // 4. 判断用户请求的是否为 /about.html 关于页面
  if (url === &#39;/&#39; || url === &#39;/index.html&#39;) {
    content = &#39;&lt;h1&gt;首页&lt;/h1&gt;&#39;
  } else if (url === &#39;/about.html&#39;) {
    content = &#39;&lt;h1&gt;关于页面&lt;/h1&gt;&#39;
  }
  // 5. 设置 Content-Type 响应头，防止中文乱码
  res.setHeader(&#39;Content-Type&#39;, &#39;text/html; charset=utf-8&#39;)
  // 6. 使用 res.end() 把内容响应给客户端
  res.end(content)
})

server.listen(80, () =&gt; {
  console.log(&#39;server running at http://127.0.0.1&#39;)
})

</code></pre>
<h3 id="-clock-web-">实现clock时钟web服务器</h3>
<h4 id="-">核心思路</h4>
<p>把文件的实际存放路径，<strong>作为</strong>每个资源的请求 url 地址。</p>
<p><img src=".\assets\clock的web服务器.png" alt=""></p>
<h4 id="-">实现步骤</h4>
<pre><code class="lang-javascript">// 1.1 导入 http 模块
const http = require(&#39;http&#39;)
// 1.2 导入 fs 模块
const fs = require(&#39;fs&#39;)
// 1.3 导入 path 模块
const path = require(&#39;path&#39;)

// 2.1 创建 web 服务器
const server = http.createServer()
// 2.2 监听 web 服务器的 request 事件
server.on(&#39;request&#39;, (req, res) =&gt; {
  // 3.1 获取到客户端请求的 URL 地址
  //     /clock/index.html
  //     /clock/index.css
  //     /clock/index.js
  const url = req.url
  // 3.2 把请求的 URL 地址映射为具体文件的存放路径
  // const fpath = path.join(__dirname, url)
  // 5.1 预定义一个空白的文件存放路径
  let fpath = &#39;&#39;
  if (url === &#39;/&#39;) {
    fpath = path.join(__dirname, &#39;./clock/index.html&#39;)
  } else {
    //     /index.html
    //     /index.css
    //     /index.js
    fpath = path.join(__dirname, &#39;/clock&#39;, url)
  }

  // 4.1 根据“映射”过来的文件路径读取文件的内容
  fs.readFile(fpath, &#39;utf8&#39;, (err, dataStr) =&gt; {
    // 4.2 读取失败，向客户端响应固定的“错误消息”
    if (err) return res.end(&#39;404 Not found.&#39;)
    // 4.3 读取成功，将读取成功的内容，响应给客户端
    res.end(dataStr)
  })
})
// 2.3 启动服务器
server.listen(80, () =&gt; {
  console.log(&#39;server running at http://127.0.0.1&#39;)
})

</code></pre>
<h1 id="-">三、模块化</h1>
<h2 id="3-1-">3.1 模块化的基本概念</h2>
<h3 id="-">什么是模块化</h3>
<p>​        <strong>模块化</strong>是指解决一个复杂问题时，自顶向下逐层把系统划分成若干模块的过程。对于整个系统来说，模块是可组合、分解和更换的单元。</p>
<p>​        编程领域中的模块化，就是<strong>遵守固定的规则</strong>，把一个大文件拆成独立并互相依赖的多个小模块。</p>
<p>​    把代码进行模块化拆分的好处：</p>
<p>​    ① 提高了代码的复用性</p>
<p>​    ② 提高了代码的可维护性</p>
<p>​    ③ 可以实现按需加载</p>
<h3 id="-">模块化规范</h3>
<p><strong>模块化规范</strong>就是对代码进行模块化的拆分与组合时，需要遵守的那些规则。</p>
<p>例如：</p>
<p>⚫ 使用什么样的语法格式来引用模块</p>
<p>⚫ 在模块中使用什么样的语法格式向外暴露成员</p>
<p><strong>模块化规范的好处</strong>：大家都遵守同样的模块化规范写代码，降低了沟通的成本，极大方便了各个模块之间的相互调用，利人利己。</p>
<h2 id="3-2-node-js-">3.2 Node.js中模块化</h2>
<h3 id="-">模块的分类</h3>
<p>Node.js 中根据模块来源的不同，将模块分为了 3 大类，分别是：</p>
<p>⚫ 内置模块（内置模块是由 Node.js 官方提供的，例如 fs、path、http 等）</p>
<p>⚫ 自定义模块（用户创建的每个 .js 文件，都是自定义模块）</p>
<p>⚫ 第三方模块（由第三方开发出来的模块，并非官方提供的内置模块，也不是用户创建的自定义模块，使用前需要先下载）</p>
<h3 id="-">加载模块</h3>
<pre><code class="lang-javascript">// 1. 加载内置的fs模块
const fs = require(&#39;fs&#39;)

// 2. 加载用户的自定义模块
const custom = require(&#39;./custom.js&#39;)

// 3. 加载第三方模块
const moment = require(&#39;moment&#39;)
</code></pre>
<h3 id="-">模块作用域</h3>
<p>​        和函数作用域类似，在自定义模块中定义的变量、方法等成员，只能在当前模块内被访问，这种模块级别的访问限制，叫做<strong>模块作用域</strong>。</p>
<pre><code class="lang-javascript">const custom = require(&#39;./08.模块作用域&#39;)

console.log(custom)
</code></pre>
<pre><code class="lang-javascript">// 表示08.模块作用域
const username = &#39;张三&#39;

function sayHello() {
  console.log(&#39;大家好，我是&#39; + username)
}
</code></pre>
<p>​    模块作用域的好处，防止了全局变量污染的问题</p>
<h3 id="-">向外共享模块作用域中的成员</h3>
<h4 id="module-">module对象</h4>
<pre><code>console.log(module)
</code></pre><h4 id="module-exports-">module.exports对象</h4>
<p>​    在自定义模块中，可以使用 module.exports 对象，将模块内的成员共享出去，供外界使用。外界用 require() 方法导入自定义模块时，得到的就是 module.exports 所指向的对象。</p>
<pre><code class="lang-javascript">// 在一个自定义模块中，默认情况下， module.exports = {}

const age = 20

// 向 module.exports 对象上挂载 username 属性
module.exports.username = &#39;zs&#39;
// 向 module.exports 对象上挂载 sayHello 方法
module.exports.sayHello = function() {
  console.log(&#39;Hello!&#39;)
}
module.exports.age = age

// 让 module.exports 指向一个全新的对象
module.exports = {
  nickname: &#39;小黑&#39;,
  sayHi() {
    console.log(&#39;Hi!&#39;)
  }
}
</code></pre>
<pre><code class="lang-javascript">// 在外界使用 require 导入一个自定义模块的时候，得到的成员，
// 就是 那个模块中，通过 module.exports 指向的那个对象
const m = require(&#39;./11.自定义模块&#39;)

console.log(m)

</code></pre>
<h4 id="-">共享成员注意点</h4>
<p>​    使用 require() 方法导入模块时，导入的结果，<strong>永远以 module.exports 指向的对象为准</strong>。</p>
<h4 id="exports-">exports对象</h4>
<p>​        由于 module.exports 单词写起来比较复杂，为了简化向外共享成员的代码，Node 提供了 exports 对象。默认情况下，exports 和 module.exports 指向同一个对象。最终共享的结果，还是以 module.exports 指向的对象为准。</p>
<pre><code class="lang-javascript">// console.log(exports)
// console.log(module.exports)

// console.log(exports === module.exports)

const username = &#39;zs&#39;

module.exports.username = username
exports.age = 20
exports.sayHello = function () {
  console.log(&#39;大家好！&#39;)
}

// 最终，向外共享的结果，永远都是 module.exports 所指向的对象

</code></pre>
<pre><code class="lang-javascript">const m = require(&#39;./13.exports对象&#39;)
console.log(m)
</code></pre>
<h3 id="node-js-">Node.js中的模块化规范</h3>
<p>Node.js 遵循了 CommonJS 模块化规范，CommonJS 规定了模块的特性和各模块之间如何相互依赖。</p>
<p>CommonJS 规定：</p>
<p>① 每个模块内部，module 变量代表当前模块。</p>
<p>② module 变量是一个对象，它的 exports 属性（即 module.exports）是对外的接口。</p>
<p>③ 加载某个模块，其实是加载该模块的 module.exports 属性。require() 方法用于加载模块。</p>
<h2 id="3-3-npm-">3.3 npm与包</h2>
<h3 id="-">包</h3>
<h4 id="-">概念</h4>
<p>​    Node.js 中的第三方模块又叫做包。就像电脑和计算机指的是相同的东西，第三方模块和包指的是同一个概念，只不过叫法不同。</p>
<hr>

<h4 id="-">来源</h4>
<p>​    不同于 Node.js 中的内置模块与自定义模块，包是由第三方个人或团队开发出来的，免费供所有人使用。</p>
<p><strong>注意</strong>：Node.js 中的包都是免费且开源的，不需要付费即可免费下载使用。</p>
<hr>

<h4 id="-">原因</h4>
<p>​        由于 Node.js 的内置模块仅提供了一些底层的 API，导致在基于内置模块进行项目开发的时，效率很低。包是基于内置模块封装出来的，提供了更高级、更方便的 API，极大的提高了开发效率。包和内置模块之间的关系，类似于 jQuery 和 浏览器内置 API 之间的关系。</p>
<hr>
<h4 id="-">下载包</h4>
<p>​        国外有一家 IT 公司，叫做 <strong>npm, Inc.</strong> 这家公司旗下有一个非常著名的网站： <a href="https://www.npmjs.com/">https://www.npmjs.com/</a> ，它是<strong>全球最大的包共享平台</strong>，你可以从这个网站上搜索到任何你需要的包，只要你有足够的耐心！</p>
<p>​        到目前为止，全球约 1100 多万的开发人员，通过这个包共享平台，开发并共享了超过 120 多万个包 供我们使用。</p>
<p>​        <strong>npm, Inc. 公司</strong>提供了一个地址为 <a href="https://registry.npmjs.org/">https://registry.npmjs.org/</a> 的服务器，来对外共享所有的包，我们可以从这个服务器上下载自己所需要的包。</p>
<p><strong>注意：</strong></p>
<p>⚫ 从 <a href="https://www.npmjs.com/">https://www.npmjs.com/</a> 网站上搜索自己所需要的包</p>
<p>⚫ 从 <a href="https://registry.npmjs.org/">https://registry.npmjs.org/</a> 服务器上下载自己需要的包</p>
<hr>
<h3 id="npm">npm</h3>
<h4 id="npm-">npm初体验</h4>
<h5 id="1-">1 格式化时间传统做法</h5>
<pre><code class="lang-javascript">// 1. 定义格式化时间的方法
function dateFormat(dtStr) {
  const dt = new Date(dtStr)

  const y = dt.getFullYear()
  const m = padZero(dt.getMonth() + 1)
  const d = padZero(dt.getDate())

  const hh = padZero(dt.getHours())
  const mm = padZero(dt.getMinutes())
  const ss = padZero(dt.getSeconds())

  return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
}

// 定义补零的函数
function padZero(n) {
  return n &gt; 9 ? n : &#39;0&#39; + n
}

module.exports = {
  dateFormat
}

</code></pre>
<pre><code class="lang-javascript">// 导入自定义的格式化时间的模块
const TIME = require(&#39;./15.dateFormat&#39;)

// 调用方法，进行时间的格式化
const dt = new Date()
console.log(dt)
const newDT = TIME.dateFormat(dt)
console.log(newDT)

</code></pre>
<h5 id="2-">2 格式化时间高级做法</h5>
<p>① 使用 npm 包管理工具，在项目中安装格式化时间的包 moment</p>
<p>② 使用 require() 导入格式化时间的包</p>
<p>③ 参考 moment 的官方 API 文档对时间进行格式化</p>
<pre><code class="lang-javascript">// 1. 导入需要的包
// 注意：导入的名称，就是装包时候的名称
const moment = require(&#39;moment&#39;)

const dt = moment().format(&#39;YYYY-MM-DD HH:mm:ss&#39;)
console.log(dt)

</code></pre>
<h5 id="3-">3 在项目中安装包的命令</h5>
<pre><code>npm install 包的完整名称

或者
npm i 完整的包名称
</code></pre><h5 id="4-">4 初次安装后多了哪些文件</h5>
<p>​        初次装包完成后，在项目文件夹下多一个叫做 node_modules 的文件夹和 package-lock.json 的配置文件。</p>
<p>其中：</p>
<p>​        node_modules 文件夹用来存放所有已安装到项目中的包。require() 导入第三方包时，就是从这个目录中查找并加载包。</p>
<p>​        package-lock.json 配置文件用来记录 node_modules 目录下的每一个包的下载信息，例如包的名字、版本号、下载地址等。</p>
<p>​        注意：程序员不要手动修改 node_modules 或 package-lock.json 文件中的任何代码，    npm 包管理工具会自动维护它们。</p>
<h5 id="5-">5 安装指定版本的包</h5>
<p>​        默认情况下，使用 npm install 命令安装包的时候，会自动安装最新版本的包。如果需要安装指定版本的包，可以在包名之后，通过 @ 符号指定具体的版本，例如：</p>
<pre><code>npm i moment@2.22.2
</code></pre><hr>
<h5 id="6-">6 包的语义化版本规范</h5>
<p>包的版本号是以“点分十进制”形式进行定义的，总共有三位数字，例如 <strong>2.24.0</strong></p>
<p>其中每一位数字所代表的的含义如下：</p>
<p>第1位数字：大版本</p>
<p>第2位数字：功能版本</p>
<p>第3位数字：Bug修复版本</p>
<p>版本号提升的规则：只要前面的版本号增长了，则后面的版本号归零。</p>
<hr>
<h3 id="-">包管理配置文件</h3>
<h4 id="-">多人协作的问题</h4>
<p><img src=".\assets\多人协作的问题.png" alt=""></p>
<p>整个项目的体积是 30.4M</p>
<p>第三方包的体积是 28.8M</p>
<p>项目源代码的体积 1.6M</p>
<p>遇到的问题：第三方包的体积过大，不方便团队成员之间共享项目源代码。</p>
<p>解决方案：共享时剔除node_modules</p>
<hr>
<h4 id="-">如何记录项目中安装了哪些包</h4>
<p>​        在项目根目录中，创建一个叫做 package.json 的配置文件，即可用来记录项目中安装了哪些包。从而方便剔除node_modules 目录之后，在团队成员之间共享项目的源代码。</p>
<p>​        <strong>注意</strong>：今后在项目开发中，一定要把 node_modules 文件夹，添加到 .gitignore 忽略文件中。</p>
<hr>
<h4 id="-package-json">快速创建package.json</h4>
<p>npm 包管理工具提供了一个快捷命令，可以在执行命令时所处的目录中，快速创建 package.json 这个包管理</p>
<p>配置文件：</p>
<pre><code class="lang-javascript">npm init -y
</code></pre>
<p>注意：</p>
<p>① 上述命令只能在英文的目录下成功运行！所以，项目文件夹的名称一定要使用英文命名，不要使用中文，不能出现空格。</p>
<p>② 运行 npm install 命令安装包的时候，npm 包管理工具会自动把包的名称和版本号，记录到 package.json 中。</p>
<hr>
<h4 id="dependencies">dependencies</h4>
<p>​    package-lock.json 文件中，有一个 dependencies 节点，专门用来记录您使用 npm install 命令安装了哪些包。</p>
<hr>
<h4 id="-">一次性安装所有的包</h4>
<p>​        当我们拿到一个剔除了 node_modules 的项目之后，需要先把所有的包下载到项目中，才能将项目运行起来。</p>
<p>可以运行 npm install 命令（或 npm i）一次性安装所有的依赖包：</p>
<p><img src=".\assets\安装依赖包.png" alt=""></p>
<h4 id="-">卸载包</h4>
<p>可以运行 npm uninstall 命令，来卸载指定的包：</p>
<p>注意：npm uninstall 命令执行成功后，会把卸载的包，自动从 package.json 的 dependencies 中移除掉.</p>
<h4 id="devdependencies-">devDependencies节点</h4>
<p>​        如果某些包<strong>只在项目开发阶段</strong>会用到，在<strong>项目上线之后不会用到</strong>，则建议把这些包记录到 devDependencies 节点中。与之对应的，如果某些包在开发和项目上线之后都需要用到，则建议把这些包记录到 dependencies 节点中。</p>
<p>​        您可以使用如下的命令，将包记录到 devDependencies 节点中：</p>
<p><img src=".\assets\dev节点.png" alt=""></p>
<hr>

<h3 id="-">解决下包速度慢的问题</h3>
<h4 id="1-">1 为什么下包速度慢</h4>
<p>​        在使用 npm 下包的时候，默认从国外的 <a href="https://registry.npmjs.org/">https://registry.npmjs.org/</a> 服务器进行下载，此时，网络数据的传输需要经</p>
<p>过漫长的海底光缆，因此下包速度会很慢。</p>
<p>扩展阅读 - 海底光缆：</p>
<p>⚫ <a href="https://baike.baidu.com/item/%E6%B5%B7%E5%BA%95%E5%85%89%E7%BC%86/4107830">https://baike.baidu.com/item/%E6%B5%B7%E5%BA%95%E5%85%89%E7%BC%86/4107830</a></p>
<p>⚫ <a href="https://baike.baidu.com/item/%E4%B8%AD%E7%BE%8E%E6%B5%B7%E5%BA%95%E5%85%89%E7%BC%">https://baike.baidu.com/item/%E4%B8%AD%E7%BE%8E%E6%B5%B7%E5%BA%95%E5%85%89%E7%BC%</a></p>
<p>86/10520363</p>
<p>⚫ <a href="https://baike.baidu.com/item/APG/23647721?fr=aladdin">https://baike.baidu.com/item/APG/23647721?fr=aladdin</a></p>
<hr>
<h4 id="2-npm-">2 淘宝NPM镜像服务器</h4>
<p><img src=".\assets\下包速度问题1.png" alt=""></p>
<p>​        淘宝在国内搭建了一个服务器，专门把国外官方服务器上的包同步到国内的服务器，然后在国内提供下包的服务。从而极大的提高了下包的速度。</p>
<p><img src=".\assets\下包速度问题2.png" alt=""></p>
<p>扩展：</p>
<p><strong>镜像</strong>（Mirroring）是一种文件存储形式，一个磁盘上的数据在另一个磁盘上存在一个完全相同的副本即为镜像。</p>
<hr>
<h4 id="3-npm-">3 切换npm的下载镜像源</h4>
<p>下包的镜像源，指的就是下包的服务器地址。</p>
<p><img src=".\assets\镜像源.png" alt=""></p>
<hr>
<h4 id="4-nrm">4 nrm</h4>
<p>​        为了更方便的切换下包的镜像源，我们可以安装 <strong>nrm</strong> 这个小工具，利用 nrm 提供的终端命令，可以快速查看和切换下包的镜像源。</p>
<p><img src=".\assets\nrm工具.png" alt=""></p>
<hr>
<h3 id="-">包的分类</h3>
<p>使用 npm 包管理工具下载的包，共分为两大类，分别是：</p>
<p>⚫ 项目包</p>
<p>⚫ 全局包</p>
<h4 id="1-">1 项目包</h4>
<p>​    那些被安装到项目的 node_modules 目录中的包，都是项目包。</p>
<p>​    项目包又分为两类，分别是：</p>
<p>⚫ 开发依赖包（被记录到 devDependencies 节点中的包，只在开发期间会用到）</p>
<p>⚫ 核心依赖包（被记录到 dependencies 节点中的包，在开发期间和项目上线之后都会用到）</p>
<p><img src=".\assets\项目包.png" alt=""></p>
<hr>
<h4 id="2-">2 全局包</h4>
<p>在执行 npm install 命令时，如果提供了 -g 参数，则会把包安装为全局包。</p>
<p>全局包会被安装到 C:\Users\用户目录\AppData\Roaming\npm\node_modules 目录下。</p>
<p><img src=".\assets\全局包.png" alt=""></p>
<p>注意：</p>
<p>① 只有工具性质的包，才有全局安装的必要性。因为它们提供了好用的终端命令。</p>
<p>② 判断某个包是否需要全局安装后才能使用，可以参考官方提供的使用说明即可。</p>
<hr>
<h4 id="3-i5ting_toc">3 i5ting_toc</h4>
<p>i5ting_toc 是一个可以把 md 文档转为 html 页面的小工具，使用步骤如下：</p>
<p><img src=".\assets\i5ting_toc.png" alt=""></p>
<h3 id="-">规范的包结构</h3>
<p>​        在清楚了包的概念、以及如何下载和使用包之后，接下来，我们深入了解一下包的内部结构。</p>
<p>​    一个规范的包，它的组成结构，必须符合以下 3 点要求：</p>
<p>​    ① 包必须以单独的目录而存在</p>
<p>​    ② 包的顶级目录下要必须包含 package.json 这个包管理配置文件</p>
<p>​    ③ package.json 中必须包含 name，version，main 这三个属性，分别代表包的名字、版本号、包的入口。</p>
<p>​        注意：以上 3 点要求是一个规范的包结构必须遵守的格式，关于更多的约束，可以参考如下网址：</p>
<p>​        <a href="https://yarnpkg.com/zh-Hans/docs/package-json">https://yarnpkg.com/zh-Hans/docs/package-json</a></p>
<hr>
<h3 id="-">开发属于自己的包</h3>
<h4 id="1-">1 需要实现的功能</h4>
<p>① 格式化日期</p>
<p>② 转义 HTML 中的特殊字符</p>
<p>③ 还原 HTML 中的特殊字符</p>
<hr>
<p>888</p>
<hr>



<h4 id="2-">2 初始化包的基本结构</h4>
<h4 id="3-package-json">3 初始化package.json</h4>
<h4 id="4-index-js-">4 在index.js中定义格式化时间方法</h4>
<h4 id="5-index-js-html-">5 在index.js中定义转义HTML的方法</h4>
<h4 id="6-index-js-html-">6 在index.js中定义还原HTML的方法</h4>
<h4 id="7-">7 将不同的功能进行模块化拆分</h4>
<h4 id="8-">8 编写包的说明文档</h4>
<h3 id="-">发布包</h3>
<h4 id="1-npm-">1 注册npm账号</h4>
<h4 id="2-npm-">2 登录npm账号</h4>
<h4 id="3-npm">3 把包发布到npm</h4>
<h4 id="4-">4 删除已发布的包</h4>
<h2 id="3-4-">3.4 模块的加载机制</h2>
<h3 id="-">优先从缓存中加载</h3>
<h3 id="-">内置模块的加载机制</h3>
<h3 id="-">自定义模块的加载机制</h3>
<h3 id="-">第三模块的加载机制</h3>
<h3 id="-">目录作为模块</h3>

          	</article>
        </div>
		</div>
  </body>
</html>
<script type="text/javascript" src="toc/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="toc/js/jquery.ztree.all-3.5.min.js"></script>
<script type="text/javascript" src="toc/js/ztree_toc.js"></script>
<script type="text/javascript" src="toc_conf.js"></script>

<SCRIPT type="text/javascript" >
<!--
$(document).ready(function(){
    var css_conf = eval(markdown_panel_style);
    $('#readme').css(css_conf)
    
    var conf = eval(jquery_ztree_toc_opts);
		$('#tree').ztree_toc(conf);
});
//-->
</SCRIPT>